#include "LightOnOff.h"

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

using namespace app::Clusters;
using namespace app::Clusters::OnOff;

namespace {
constexpr uint16_t kOnOffClusterRevision = 1u;

constexpr CommandId onOffIncomingCommands[] = {
        Commands::Off::Id,
        Commands::On::Id,
        Commands::Toggle::Id,
        Commands::OffWithEffect::Id,
        Commands::OnWithRecallGlobalScene::Id,
        Commands::OnWithTimedOff::Id,
        kInvalidCommandId,
    };

// Declare On/Off cluster attributes
constexpr DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(onOffAttrs)
    DECLARE_DYNAMIC_ATTRIBUTE(Attributes::OnOff::Id, BOOLEAN, 1, 0), /* on/off */
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

constexpr EmberAfCluster onOffCluster = DECLARE_DYNAMIC_CLUSTER(
    OnOff::Id,
    onOffAttrs,
    ZAP_CLUSTER_MASK(SERVER),
    onOffIncomingCommands,
    nullptr);
}

using namespace chip::app::Clusters;

LightOnOff::LightOnOff(const ::BasicInformation* node)
    : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "LightOnOff");
    mClusters.push_back(onOffCluster);
    mOn = false;
}

bool LightOnOff::IsOn() const {
    return mOn;
}

void LightOnOff::UpdateOnOff(bool on) {
    if (mOn == on) {
        return;
    }
    mOn = on;
    ChipLogProgress(DeviceLayer, "Device[%s]: %s", mInfo->GetLabel().c_str(), mOn ? "ON" : "OFF");
    NotifyStatusChanged(Id, Attributes::OnOff::Id);
    NotifyStatusChanged(LevelControl::Id, LevelControl::Attributes::CurrentLevel::Id);
}

void LightOnOff::SetOnOff(bool on) {
    DataBlock block(Path(Id, Attributes::OnOff::Id), on);
    SendMessage(&block);

    // 立马上报一个状态给app，草坪灯会延时上报
    UpdateOnOff(on);
}

ChipError LightOnOff::OnReport(const DataBlock* block) {
    if (block->path.clusterId != Id) {
        return BridgedDevice::OnReport(block);
    }
    const bool newValue = block->data.asBool();
    const bool changed = newValue != mOn;
    mOn = newValue;
    ChipLogProgress(DeviceLayer, "Device[%s]: %s", mInfo->GetLabel().c_str(), mOn ? "ON" : "OFF");
    if (changed) {
        NotifyStatusChanged(Id, Attributes::OnOff::Id);
    }
    return CHIP_NO_ERROR;
}

ChipError LightOnOff::OnReadAttributes() {
    GetRemoteAttribute(Id, Attributes::OnOff::Id);
    return CHIP_NO_ERROR;
}


Protocols::InteractionModel::Status LightOnOff::ReadAttribute(
    ClusterId clusterId,
    AttributeId attributeId,
    uint8_t* buffer,
    uint16_t maxReadLength) {
    ChipLogProgress(DeviceLayer, "OnOffAttributes: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);
    if (clusterId != Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }

    if ((attributeId == Attributes::OnOff::Id) && (maxReadLength == 1)) {
        *buffer = this->IsOn() ? 1 : 0;
    } else if ((attributeId == Attributes::ClusterRevision::Id) && (maxReadLength == 2)) {
        *buffer = kOnOffClusterRevision;
    } else {
        return Protocols::InteractionModel::Status::UnsupportedRead;
    }
    return Protocols::InteractionModel::Status::Success;
}

Protocols::InteractionModel::Status LightOnOff::WriteAttribute(
    ClusterId clusterId,
    const EmberAfAttributeMetadata* attributeMetadata,
    uint8_t* buffer) {
    ChipLogDetail(DeviceLayer, "WriteAttribute clsterId=%04x", clusterId);
    if (clusterId != Id) {
        return BridgedDevice::WriteAttribute(clusterId, attributeMetadata, buffer);
    }

    if (attributeMetadata->attributeId == Attributes::OnOff::Id) {
        if (*buffer) {
            this->SetOnOff(true);
        } else {
            this->SetOnOff(false);
        }
    } else {
        return Protocols::InteractionModel::Status::UnsupportedWrite;
    }
    return Protocols::InteractionModel::Status::Success;
}

